package com.service.business.member.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.service.business.base.service.CoinsPriceService;
import com.service.business.base.service.ConfigService;
import com.service.business.member.controller.rep.MemberAccumulatedRep;
import com.service.business.member.controller.rep.MemberJARep;
import com.service.business.member.dto.MiningRecord;
import com.service.business.member.service.*;
import com.service.business.order.service.OrderProductHrComboService;
import com.service.business.support.SessionUtil;
import com.service.business.utils.MemberAccountUtil;
import com.service.core.rest.request.PageRequest;
import com.service.core.rest.response.CommonPageRep;
import com.service.dao.constants.ConfigConstants;
import com.service.dao.dto.HrComboOrder;
import com.service.dao.enums.CoinsEnum;
import com.service.dao.enums.HashRateOrderEnums;
import com.service.dao.enums.MemberJAType;
import com.service.dao.mapper.JournalAccountMapper;
import com.service.dao.model.*;
import com.service.dao.po.MemberCache;
import com.service.utility.common.MathUtil;
import com.service.utility.modelmapper.ModelMapperUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <dl>
 * <dt>back-end</dt>
 * <dd>Description:会员账户流水</dd>
 * <dd>Copyright: Copyright (C) 2015</dd>
 * <dd>Company: </dd>
 * <dd>CreateDate: 2019年09月24日</dd>
 * </dl>
 *
 * @author
 */
@Slf4j
@Service
public class MemberJAServiceImpl extends ServiceImpl<JournalAccountMapper, JournalAccount> implements MemberJAService {

    @Autowired
    private SessionUtil sessionUtil;
    @Autowired
    private MemberService memberService;
    @Autowired
    private ConfigService configService;
    @Autowired
    private MemberOutService memberOutService;
    @Autowired
    private MemberCacheService memberCacheService;
    @Autowired
    private MemberMiningOrderService miningOrderService;
    @Autowired
    private OrderProductHrComboService orderProductHrComboService;
    @Autowired
    private MemberAwardByHrComboOrderService memberAwardService;
    @Override
    public MemberAccumulatedRep getTotalAccumulated() {
        Integer memberId = this.sessionUtil.getUser().getUserId();
        MemberCache memberCache = memberCacheService.getMemberCache(memberId);
        BigDecimal multiplyNum = MathUtil.parseBigDecimal(configService.getConfigByName(ConfigConstants.TOTAL_CONSUMPTION_MULTIPLE).getConfValue());
        BigDecimal totalMiningFrostNum = miningOrderService.totalMiningFrostNum(memberId, CoinsEnum.FIL.getCode(),null,null);
        BigDecimal totalMiningReleaseNum = miningOrderService.totalMiningReleaseNum(memberId, CoinsEnum.FIL.getCode(),null,null);
        BigDecimal totalEffectiveRate = orderProductHrComboService.totalEffectiveHrRateLargeThanZeroByMemberId(memberId);
        return MemberAccumulatedRep.builder()
                .totalAwardIncome(memberCacheService.getMemberTotalAward(memberCache).setScale(8,BigDecimal.ROUND_DOWN))
                .totalMiningAward(memberCache.getHashRateAward().setScale(8,BigDecimal.ROUND_DOWN))
                .totalMiningFrost(totalMiningFrostNum.subtract(totalMiningReleaseNum).setScale(8,BigDecimal.ROUND_DOWN))
                .totalMiningRelease(totalMiningReleaseNum.setScale(8,BigDecimal.ROUND_DOWN))
                .totalEffectiveRate(totalEffectiveRate.setScale(8,BigDecimal.ROUND_DOWN))
                .outNum(memberCache.getTotalConsumption().multiply(multiplyNum).setScale(8,BigDecimal.ROUND_DOWN))
                .build();
    }

    @Override
    public CommonPageRep<MemberJARep> pageAccumulated(CoinsEnum coin, PageRequest request) {
        Integer memberId = this.sessionUtil.getUser().getUserId();
        LambdaQueryWrapper<JournalAccount> queryWrapper = new QueryWrapper<JournalAccount>().lambda()
                .eq(JournalAccount::getCoinsId, coin.getCode())
                .eq(JournalAccount::getMemberId, memberId)
                .orderByDesc(JournalAccount::getId);
        if (ObjectUtils.nullSafeEquals(coin.getCode(), CoinsEnum.USDF.getCode())) {
            MemberOut memberOut = memberOutService.getLastMemberOutRecord(memberId);
            queryWrapper.in(JournalAccount::getJaType, MemberJAType.getAwardIncomeType());
            if (!ObjectUtils.isEmpty(memberOut)) {
                queryWrapper.ge(JournalAccount::getCreateTime, memberOut.getCreateTime());
            }
        } else {
            queryWrapper.in(JournalAccount::getJaType, MemberJAType.getMiningFrostType());
        }
        Page<JournalAccount> page = PageHelper.startPage(request.getPageNo(), request.getPageSize());
        list(queryWrapper);
        return CommonPageRep.buildResultRep(page, page.getResult().stream()
                .map(item -> ModelMapperUtil.getStrictModelMapper().map(item, MemberJARep.class))
                .collect(Collectors.toList()));
    }

    @Override
    public CommonPageRep<MemberJARep> pageMemberJA(CoinsEnum coin, PageRequest request) {
        Integer memberId = this.sessionUtil.getUser().getUserId();
        Page<JournalAccount> page = PageHelper.startPage(request.getPageNo(), request.getPageSize());

        LambdaQueryWrapper<JournalAccount> queryWrapper = new QueryWrapper<JournalAccount>().lambda()
                .eq(JournalAccount::getCoinsId, coin.getCode())
                .eq(JournalAccount::getMemberId, memberId)
                .orderByDesc(JournalAccount::getId);
        queryWrapper.notIn(JournalAccount::getJaType, MemberJAType.getMemberJAWithoutType());
        list(queryWrapper);
        List<MemberJARep> resultList = page.getResult()
                .stream().map(item -> {
                    MemberJARep resultItem = ModelMapperUtil.getStrictModelMapper().map(item, MemberJARep.class);

                    JournalAccount transfer = null;
                    if (ObjectUtils.nullSafeEquals(resultItem.getJaType(), MemberJAType.TURN_OUT.getCode())) {
                        transfer = getOne(new QueryWrapper<JournalAccount>().lambda().eq(JournalAccount::getJaId, item.getId()).last("limit 1"));
                    } else if (ObjectUtils.nullSafeEquals(resultItem.getJaType(), MemberJAType.TURN_IN.getCode())) {
                        transfer = getById(item.getId());
                    } else {
                        return resultItem;
                    }
                    Member member = memberService.getById(transfer.getMemberId());
                    if (ObjectUtils.isEmpty(member)) {
                        resultItem.setJaRemark("");
                        return resultItem;
                    }
                    resultItem.setJaRemark(MemberAccountUtil.getUserAccountSuffix(member.getUserAccount()));
                    return resultItem;
                }).collect(Collectors.toList());
        return CommonPageRep.buildResultRep(page, resultList);
    }

    @Override
    public CommonPageRep<MemberJARep> pageMemberJA(CoinsEnum coin,Integer orderId, PageRequest request) {
        Integer memberId = this.sessionUtil.getUser().getUserId();
        Page<JournalAccount> page = PageHelper.startPage(request.getPageNo(), request.getPageSize());

        LambdaQueryWrapper<JournalAccount> queryWrapper = new QueryWrapper<JournalAccount>().lambda()
                .eq(JournalAccount::getCoinsId, coin.getCode())
                .eq(JournalAccount::getMemberId, memberId)
                .eq(JournalAccount::getOrderId, orderId)
                .eq(JournalAccount::getId, MemberJAType.MINING.getCode())
                .orderByDesc(JournalAccount::getId);
        queryWrapper.notIn(JournalAccount::getJaType, MemberJAType.getMemberJAWithoutType());
        list(queryWrapper);
        List<MemberJARep> resultList = page.getResult()
                .stream().map(item -> {
                    MemberJARep resultItem = ModelMapperUtil.getStrictModelMapper().map(item, MemberJARep.class);
                    JournalAccount transfer = null;
                    if (ObjectUtils.nullSafeEquals(resultItem.getJaType(), MemberJAType.TURN_OUT.getCode())) {
                        transfer = getOne(new QueryWrapper<JournalAccount>().lambda().eq(JournalAccount::getJaId, item.getId()).last("limit 1"));
                    } else if (ObjectUtils.nullSafeEquals(resultItem.getJaType(), MemberJAType.TURN_IN.getCode())) {
                        transfer = getById(item.getId());
                    } else {
                        return resultItem;
                    }
                    Member member = memberService.getById(transfer.getMemberId());
                    if (ObjectUtils.isEmpty(member)) {
                        resultItem.setJaRemark("");
                        return resultItem;
                    }
                    resultItem.setJaRemark(MemberAccountUtil.getUserAccountSuffix(member.getUserAccount()));
                    return resultItem;
                }).collect(Collectors.toList());
        return CommonPageRep.buildResultRep(page, resultList);
    }


    @Override
    public void getMemberIncome(Integer memberId, MemberCache.MemberCacheBuilder builder, MemberOut memberOut) {
        Date startTime = null, endTime = null;
        if (!ObjectUtils.isEmpty(memberOut)) {
            startTime = memberOut.getCreateTime();
            endTime = new Date();
        }
        List<JournalAccount> incomeList = baseMapper.listTotalAccumulatedIncome(memberId, MemberJAType.getAwardIncomeType(), startTime, endTime);
        List<JournalAccount> miningList = baseMapper.listTotalAccumulatedIncome(memberId, MemberJAType.getMiningIncomeType(), null, null);
        incomeList.addAll(miningList);
        if (ObjectUtils.isEmpty(incomeList)) {
            return;
        }
        for (JournalAccount item : incomeList) {
            switch (item.getJaType()) {
                case 11:
                    //直间奖
                    builder.directAward(item.getJaNum());
                    break;
                case 12:
                    //间接奖
                    builder.indirectAward(item.getJaNum());
                    break;
                case 13:
                    //社区奖
                    builder.communityAward(item.getJaNum());
                    break;
                case 14:
                    //节点
                    builder.nodeAward(item.getJaNum());
                    break;
                case 50:
                    //挖矿
                    builder.hashRateAward(item.getJaNum());
                    break;
                default:
                    break;
            }
        }

    }


    @Override
    public List<MiningRecord> getMiningRecord(Integer memberId, Integer orderId) {

        List<JournalAccount> jaList = list(new QueryWrapper<JournalAccount>().lambda()
                .eq(JournalAccount::getJaType, MemberJAType.MINING.getCode())
                .eq(JournalAccount::getMemberId, memberId)
                .eq(JournalAccount::getOrderId, orderId));

        return jaList.stream().map(item ->
                MiningRecord.builder().coinsName(item.getCoinsName())
                        .miningNum(item.getJaNum())
                        .createTime(item.getCreateTime())
                        .build()).collect(Collectors.toList());
    }

    @Override
    public BigDecimal getSomedayTotalStatement(Integer storeId, Date someday, List<Integer> jaType) {
        String somedayStr = null;
        if(!ObjectUtils.isEmpty(someday)){
            somedayStr = DateFormatUtils.format(someday, DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.getPattern());
        };
        return baseMapper.getSomedayTotalStatement(storeId, jaType, somedayStr);
    }

    @Override
    public BigDecimal getSomedayTotalStatement(Integer memberId, String coins, Date someday, List<Integer> jaType) {
        String somedayStr = null;
        if(!ObjectUtils.isEmpty(someday)){
            somedayStr = DateFormatUtils.format(someday, DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.getPattern());
        };
        return baseMapper.getSomedayTotalStatementByCoins(memberId, coins, jaType, somedayStr);
    }

    /**
     * @param memberId
     * @param typeList
     * @Description: 统计用户流水总量
     * @Author: ty
     * @Date: 2021/4/30 15:38
     * @param: [memberId, typeList]
     * @return: java.math.BigDecimal
     */
    @Override
    public BigDecimal totalMemberStatement(Integer memberId, List<Integer> typeList,Date someDay) {
        String somedayStr = null;
        if(!ObjectUtils.isEmpty(someDay)){
            somedayStr = DateFormatUtils.format(someDay, DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.getPattern());
        };
        return baseMapper.totalMemberStatement(memberId,typeList,somedayStr);
    }

    /**
     * @param memberIds
     * @param currentMonth
     * @Description: 统计本月业绩 排除代理商和分公司伞下业绩
     * @Author: ty
     * @Date: 2021/5/6 15:36
     * @param: [memberIds, currentMonth]
     * @return: java.math.BigDecimal
     */
    @Override
    public BigDecimal totalPerformanceCurrentMonth(Set<Integer> memberIds, Date currentMonth) {
        String currentMonthStr = DateFormatUtils.format(currentMonth, "yyyy-MM");
        return baseMapper.totalPerformanceCurrentMonth(memberIds,MemberJAType.getReleaseType(),currentMonthStr);
    }

    /**
     * @param memberId
     * @param someday
     * @param typeList
     * @Description: 判断用户的某天某流水是否存在
     * @Author: ty
     * @Date: 2021/5/28 14:17
     * @param: [memberId, someday, typeList]
     * @return: java.lang.Integer
     */
    @Override
    public Integer checkByMemberAndTypeAndSomeday(Integer memberId, String someday, List<Integer> typeList) {
        return baseMapper.checkByMemberAndTypeAndSomeday(memberId, someday, typeList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void dealMemberAward(HrComboOrder payOrder) {
        OrderProductHrCombo orderProductHrCombo = orderProductHrComboService.getById(payOrder.getOrderId());
        if (ObjectUtils.isEmpty(orderProductHrCombo)) {
            log.error("算力订单<orderId:{}>不存在", payOrder.getOrderId());
            return;
        }
        if (!ObjectUtils.nullSafeEquals(orderProductHrCombo.getOrderSource(), HashRateOrderEnums.Source.RATE_MALL.getSourceCode())) {
            log.error("算力订单<orderId:{}>非算力商城购买算力", payOrder.getOrderId());
            return;
        }
        if (ObjectUtils.nullSafeEquals(orderProductHrCombo.getReleaseAward(), HashRateOrderEnums.ReleaseAwardStatus.RELEASE.getCode())) {
            log.warn("算力订单<orderId:{}>已发送算力奖励", payOrder.getOrderId());
            return;
        }

        Member member = memberService.getMemberById(orderProductHrCombo.getMemberId());
        if (ObjectUtils.isEmpty(member)) {
            log.warn("算力订单<orderId:{}>奖励发放失败，该会员已删除", payOrder.getOrderId());
            return;
        }
        // 直推父级算力奖励
        memberAwardService.sendMemberDRHashRate(orderProductHrCombo, member.getPid());
        // 间推祖父级算力奖励
//		memberAwardService.sendMemberIRHashRate(orderProductHrCombo, member.getGid());
        // 会员团队算力奖励
        memberAwardService.sendMemberTeamHashRate(orderProductHrCombo, member);
//		upgradeByOrder(orderProductHrCombo);
        orderProductHrComboService.updateById(OrderProductHrCombo.builder()
                .id(payOrder.getOrderId())
                .releaseAward(HashRateOrderEnums.ReleaseAwardStatus.RELEASE.getCode())
                .build());
    }
}
